<?php

namespace common\service;

use support\bootstrap\Redis;
use support\SingletonTrait;

class TenantDownloadUploadQueueService
{
    use SingletonTrait;

    public const MARK_UPLOAD = 'upload';
    public const MARK_DOWNLOAD = 'download';

    /**
     * 清理掉租户里 长时间没有下载结束的任务记录
     * @param int $tenantId
     * @param $mark
     * @return void
     */
    private function clearOverdue(int $tenantId, $mark)
    {
        $inprogressKey = "tenant_$mark:" . $tenantId;
        $overdueTime = OptionsService::getInstance()->getOptionsConfigItemData('default_settings', "task_{$mark}_overdue", 3600 * 24);
        // 检查现在超时的
        $overdueTime = time() - $overdueTime;
        $overdueTaskIdList = Redis::zRangeByScore($inprogressKey, 0, $overdueTime);
        if (empty($overdueTaskIdList)) {
            return;
        }
        $errKey = "tenant_{$mark}_err:" . $tenantId;

        Redis::sRem($inprogressKey . 'inprogress_set', ...$overdueTaskIdList);
        Redis::zAdd($errKey, array_fill_keys($overdueTaskIdList, time())); // 加入下载错误的标记
        Redis::zRemRangeByScore($inprogressKey, 0, $overdueTime); // 删除下载中的标记
        Redis::zRemRangeByScore($errKey, 0, time() - 3600 * 24 * 30); // 错误的记录 保留15天
    }

    /**
     * 标记为正在下载中
     * @param int $taskId
     * @param $extraInfo
     * @param int $tenantId
     * @param $mark
     * @return bool
     */
    public function markInprogress(int $taskId, $extraInfo, int $tenantId, $mark)
    {
        $this->clearOverdue($tenantId, $mark);
        $inprogressKey = "tenant_{$mark}:" . $tenantId;
        $isMember = Redis::sIsMember($inprogressKey . 'inprogress_set', $taskId);
        if ($isMember) {
            return false;
        }
        Redis::sAdd($inprogressKey . 'inprogress_set', $taskId);
        Redis::zAdd($inprogressKey, time(), $taskId);
        // 设置当前下载信息 便于排错
        Redis::setEx($inprogressKey . 'extra_info:' . $taskId, 3600 * 24 * 7, json_encode($extraInfo));
        return true;
    }

    /**
     * 从下载中的集合中移除任务
     *
     * @param int $taskId
     * @param int $tenantId
     * @param $mark
     * @param bool $addErr
     * @return void
     */
    public function removeTaskFromInprogress(int $taskId, int $tenantId, $mark, $addErr = false)
    {
        $inprogressKey = "tenant_{$mark}:" . $tenantId;
        Redis::sRem($inprogressKey . 'inprogress_set', $taskId);
        Redis::zRem($inprogressKey, $taskId); // 删除下载中的标记
        if ($addErr) {
            $errKey = "tenant_{$mark}_err:" . $tenantId;
            Redis::zAdd($errKey, array_fill_keys([$taskId], time())); // 加入下载错误的标记
            Redis::zRemRangeByScore($errKey, 0, time() - 3600 * 24 * 30); // 错误的记录 保留30天
        }
    }

    /**
     * 标记下载失败 记录错误信息
     * @param int $taskId
     * @param int $tenantId
     * @param $mark
     * @return void
     */
    public function markInprogressErr(int $taskId, int $tenantId, $mark)
    {
        $this->clearOverdue($tenantId, $mark);
        $this->removeTaskFromInprogress($taskId, $tenantId, $mark, true);
    }

    /**
     * 查询下载中的任务id
     * @param int $tenantId
     * @param $mark
     * @return array
     */
    public function getInprogressList(int $tenantId, $mark)
    {
        $inprogressKey = "tenant_{$mark}:" . $tenantId;
        return Redis::zRangeByScore($inprogressKey, 0, time());
    }
}
